'''
pygeom -- Python Geometric Engine
vector -- Defines the Vector

A vector is an n-dimensional ordered set (in pygeom's case, the number of
dimensions is 3, which makes a Vector a convenient way to represent
two points).
'''
from __future__ import division
import math #durr

#NOTE: We do NOT inherit from GE because a vector isn't a GE, its
#an ME (Mathematical Object) ;) unfortunately there aren't enough
#of these to make a seperate ME class practical, so...object works.

#Oh, and remember, Points have the Vector property, and the
#FromVector consructor.
class Vector(object):
    def __init__(self, x, y, z):
        self.x=x
        self.y=y
        self.z=z
    #Convenience (internals)
    def _MakeVec(self, something):
        if isinstance(something, Vector):
            return something
        elif isinstance(something, (int, long, float)):
            return Vector(something, something, something)
        else:
            raise TypeError('Cannot convert %r type to Vector'%type(something))
    #Math stuff
    def __add__(self, other):
        v=self._MakeVec(other)
        return Vector(self.x+v.x, self.y+v.y, self.z+v.z)
    __radd__=__add__
    def __sub__(self, other):
        v=self._MakeVec(other)
        return Vector(self.x-v.x, self.y-v.y, self.z-v.z)
    __rsub__=__sub__
    def __mul__(self, other):
        v=self._MakeVec(other)
        return Vector(self.x*v.x, self.y*v.y, self.z*v.z)
    __rmul__=__mul__
    def __div__(self, other):
        v=self._MakeVec(other)
        return Vector(self.x/v.x, self.y/v.y, self.z/v.z)
    __rdiv__=__div__
    __truediv__=__div__
    def __iadd__(self, other):
        v=self._MakeVec(other)
        self.x+=v.x
        self.y+=v.y
        self.z+=v.z
    def __isub__(self, other):
        v=self._MakeVec(other)
        self.x-=v.x
        self.y-=v.y
        self.z-=v.z
    def __imul__(self, other):
        v=self._MakeVec(other)
        self.x*=v.x
        self.y*=v.y
        self.z*=v.z
    def __idiv__(self, other):
        v=self._MakeVec(other)
        self.x/=v.x
        self.y/=v.y
        self.z/=v.z
    __itruediv__=__idiv__
    @property
    def Length(self):
        return math.sqrt(self.x**2+self.y**2+self.z**2)
    __len__=Length #DON'T USE: PYTHON LIKES COERCING len TO INT
    def __neg__(self):
        return Vector(-self.x, -self.y, -self.z)
    @property
    def Unit(self):
        return self / self.Length
    def __repr__(self):
        return 'Vector(%s, %s, %s)'%(self.x, self.y, self.z)
    def __eq__(self, other):
        v=self._MakeVec(other) #Bad practice to pass in a coercable numeric :(
        return v.x==self.x and v.y==self.y and v.z==self.z
    def __ne__(self, other):
        return not self==other
    def Dot(self, other):
        v=self._MakeVec(other)
        return (self.x*v.x)+(self.y*v.y)+(self.z*v.z)
    def Cross(self, other):
        v=self._MakeVec(other)
        return Vector((self.y*v.z)-(self.z*v.y),
                      (self.z*v.x)-(self.x*v.z),
                      (self.x*v.y)-(self.y*v.x))
    def Angle(self, other):
        v=self._MakeVec(other)
        return math.acos(self.Dot(v)/(self.Length*v.Length))
